%%%-------------------------------------------------------------------
%%% @author Anna Orazova <anna.orazova@gmail.com>
%%% @copyright (C) 2011, Anna Orazova
%%% @doc
%%% User Interface module
%%% @end
%%% Created : 11 Nov 2011 by Anna Orazova <anna.orazova@gmail.com>
%%%-------------------------------------------------------------------

-module(ui).

-include_lib("wx/include/wx.hrl").

-behaviour(wx_object).

-export([start_link/1, init/1, terminate/2,  code_change/3,
	 handle_info/2, handle_call/3, handle_event/2]).

-record(state, 
	{
	  win,
	  parent,
	  config,
	  notebook,
	  list_torr,
	  buttons,
	  index
	 }).

-record(torrent,
	{
	  index,
	  listitem,
	  status,
	  name,
	  reference,
	  path,
	  savepath,
	  progress
	 }).


start_link(Config) ->
    wx_object:start_link(?MODULE, Config, []).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
init(Config) ->
    do_init(Config).

do_init(Config) ->
    Server = wx:new(),
    Frame = wxFrame:new(Server, -1, "Snoopy Torrent", [{size,{600, 500}},
						       {pos, {300, 100}}]),
    Panel  = wxPanel:new(Frame),

%% widgets
    B101  = wxButton:new(Panel, 101, [{label, "&Open"}]),
    wxButton:setToolTip(B101, "Choose file"),
    B102  = wxButton:new(Panel, 102, [{label, "&Start"}]),
    wxButton:disable(B102),
    wxButton:setToolTip(B102, "To start torrent"),
    B103  = wxButton:new(Panel, 103, [{label, "&Stop"}]),
    wxButton:disable(B103),
    wxButton:setToolTip(B103, "To stop torrent"),
    B104  = wxButton:new(Panel, 104, [{label, "&Remove"}]),
    wxButton:disable(B104),
    wxButton:setToolTip(B104, "To remove choosen torrent"),
    ST1001 = wxStaticText:new(Panel, 2001,"Choose a .torrent file to start download",
			      []),
    ST1002 = wxStaticText:new(Panel, 2002,"Choose an active torrent from list above",
			      []),
% Creating listview
    Notebook = wxNotebook:new(Panel, 111, [{style, ?wxBK_DEFAULT},
					  {size, {500, 400}}]),
    List = wxListCtrl:new(Notebook, [{style, ?wxLC_REPORT bor ?wxLC_SINGLE_SEL},
				     {size, {450,300}}]),
    wxListCtrl:insertColumn(List, 0, "Name", [{width, 230}]),
    wxListCtrl:insertColumn(List, 1, "Status",[{width, 120}]),
    wxListCtrl:insertColumn(List, 2, "Progress %",[{width, 120}]),
    wxNotebook:addPage(Notebook, List, "Active torrents", []),
    
 
%% Sizers
    OuterSizer   = wxBoxSizer:new(?wxHORIZONTAL),
    MainSizer   = wxBoxSizer:new(?wxVERTICAL),
    InputSizer  = wxBoxSizer:new(?wxHORIZONTAL),
    ControlSizer = wxBoxSizer:new(?wxHORIZONTAL),

    wxSizer:add(InputSizer, 20, 0, []),
    wxSizer:add(InputSizer, ST1001, []),
    wxSizer:addSpacer(InputSizer, 25), %spacer
    wxSizer:add(InputSizer, B101, []),

    wxSizer:add(ControlSizer, ST1002,[]),
    wxSizer:addSpacer(ControlSizer, 25),
    wxSizer:add(ControlSizer, B102, []),
    wxSizer:addSpacer(ControlSizer, 5),
    wxSizer:add(ControlSizer, B103, []),
    wxSizer:addSpacer(ControlSizer, 5),
    wxSizer:add(ControlSizer, B104, []),

    wxSizer:addSpacer(MainSizer, 10),  %spacer
    wxSizer:add(MainSizer, InputSizer,[]),
    wxSizer:add(MainSizer, Notebook, [{proportion, 1},{flag, ?wxEXPAND}]),
    wxSizer:addSpacer(MainSizer, 5),  %spacer
    wxSizer:add(MainSizer, ControlSizer),
    wxSizer:addSpacer(MainSizer, 5),  %spacer
     
    wxSizer:addSpacer(OuterSizer, 20), % spacer
    wxSizer:add(OuterSizer, MainSizer, []),

    wxPanel:setSizer(Panel, OuterSizer),
 
    wxFrame:show(Frame),
 
% create listeners
    wxFrame:connect(Frame, close_window),
    wxPanel:connect(Panel, command_button_clicked),
    wxListCtrl:connect(List, command_list_item_selected, []),

% return value
    {Panel, #state{win = Frame, parent=Panel, config=Config,
		   notebook = List, list_torr = [], buttons = [B102, B103, B104],
		  index = 0}}.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Async Events are handled in handle_event as in handle_info

%% When list item is selected
handle_event(#wx{obj = _ListCtrl,
		 event = #wxList{itemIndex = Item}},
	     State = #state{notebook = List,list_torr = List_torr, 
			    buttons = Buttons}) ->
    Index = Item,
    Name = wxListCtrl:getItemText(List, Index),
    Torrent = lists:keyfind(Name, #torrent.name, List_torr),

    buttons_manage(Buttons, Torrent#torrent.status),

    State_new = State#state{index = Index},
    {noreply,State_new};

%% Buttons
handle_event(#wx{id = Id, event = #wxCommand{type = command_button_clicked}},
	     State = #state{parent=Panel, notebook = List, list_torr = List_torr,
			    buttons = Buttons,index = Index}) ->
    case Id of
%% "Open" button
	101 ->
	    %% Create open file dialog
	    OpenDialog = wxFileDialog:new(Panel, [{message, 
					   "Select .torrent file to open"}]),
	    wxFileDialog:setWildcard(OpenDialog, "*.torrent"),
	    wxDialog:showModal(OpenDialog), 
	    Path = wxFileDialog:getPath(OpenDialog), % Path to the file
	    
	    %% Checks if this file already exists in the list
	    case lists:keymember(Path, #torrent.path, List_torr) of
		true -> 
		    MessageDialog = wxMessageDialog:new(Panel, 
					 "This file aready exists in the list"),
		    wxDialog:showModal(MessageDialog),
		    {noreply, State};
		_ ->
		    case Path of
			[] -> 
			    {noreply, State};
			_ ->  
			    {added, Reference, _Type, Name, _Status} = gen_server:call
						 (torrent_handler,{add_torrent, Path}),

			    %% Create save dialog
			    SaveDialog = wxDirDialog:new(Panel, [{title, 
					   "Select directory to save final files"}]), 
			    wxDialog:showModal(SaveDialog), 
			    SavePath = wxDirDialog:getPath(SaveDialog), 
						% Path to the dir

			    Status = gen_server:call(torrent_handler, 
						     {set_target, Reference, 
						      SavePath}),

			    List_torr_new = addItem({Name,Status, 
						     Reference, Path, SavePath}, 
						    List_torr, List),

			    State_new = State#state{list_torr = List_torr_new},
			    {noreply, State_new}
		    end
	    end;
%% "Start" button
	102 ->
	    Name = wxListCtrl:getItemText(List, Index),
	    Torrent = lists:keyfind(Name, #torrent.name, List_torr),

	    Status = gen_server:call(torrent_handler, 
				     {set_target, Torrent#torrent.reference,
				      Torrent#torrent.savepath}),

	    List_torr_new = lists:keyreplace(Name, #torrent.name, List_torr, 
					     Torrent#torrent{status = Status}),

	    fix_list_item(Index, Torrent#torrent.listitem, Status, Name, List,
			  Torrent#torrent.progress),
	    buttons_manage(Buttons, Status),

	    State_new = State#state{list_torr = List_torr_new},
	    {noreply, State_new};
%% "Stop" button
	103 ->
	    Status_new = "stopped",
	    Name = wxListCtrl:getItemText(List, Index),
	    Torrent = lists:keyfind(Name, #torrent.name, List_torr),

	    gen_server:cast(torrent_handler,{stop, Torrent#torrent.reference}),

	    fix_list_item(Index, Torrent#torrent.listitem, Status_new, Name, List,
			 Torrent#torrent.progress),
	    buttons_manage(Buttons, Status_new),
	    
	    List_torr_new = lists:keyreplace(Name, #torrent.name, List_torr, 
					     Torrent#torrent{status = Status_new}),
	    State_new = State#state{list_torr = List_torr_new},
	    {noreply, State_new};
%% "Remove" button
	104 ->
	    %% Dialog which is asking if user is sure in removing file.
	    PromptDialog = 
		wxMessageDialog:new(Panel, "Are you sure you want to remove this 
            file from the list? (All data will be removed)", [{style, ?wxYES_NO}]),
	    Answer = wxDialog:showModal(PromptDialog),
	    case Answer of
		?wxID_YES ->
		    Name = wxListCtrl:getItemText(List, Index),
		    Torrent = lists:keyfind(Name, #torrent.name, List_torr),

		    gen_server:cast(torrent_handler,
				    {remove, Torrent#torrent.reference}),

		    List_torr_new = lists:keydelete(Name, #torrent.name, List_torr),
		    wxListCtrl:deleteItem(List, Index),
		    State_new = State#state{list_torr = List_torr_new},
		    {noreply, State_new};
		?wxID_NO ->
		    {noreply, State}
	    end;
	_ ->
	    io:format("~p ~n", ["Unknown button"]),
	    {noreply, State}
    end;


handle_event(#wx{event=#wxClose{}}, State) ->
    io:format("~p Closing window ~n",[self()]),
    application:stop(snoopy_torrent),
    {stop, normal, State}.

%% Callbacks handled as normal gen_server callbacks
handle_info(Msg, State) ->
    io:format("Got Info ~p\n",[Msg]),
    {noreply,State}.

handle_call({progress, Progress, Reference}, _From, 
	    State = #state{index = Index, notebook = List,list_torr = List_torr}) ->
    Torrent = lists:keyfind(Reference, #torrent.reference, List_torr),
    List_torr_new = lists:keyreplace(Reference, #torrent.reference, 
			       List_torr, Torrent#torrent{progress = Progress}),
    fix_list_item(Index, Torrent#torrent.listitem, Torrent#torrent.status, 
		  Torrent#torrent.name, List,Torrent#torrent.progress),
    State_new = State#state{list_torr = List_torr_new},
    {reply,ok,State_new}.

code_change(_, _, State) ->
    {stop, ignore, State}.

terminate(_Reason, _State) ->
    ok.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Local functions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%--------------------------------------------------------------------
%% @doc
%% Adds item to ListCtrl, returns list of active torrents (List_torr).
%% @end
%%--------------------------------------------------------------------
-spec addItem({Name :: string(), Status :: string(), Reference :: reference(),
	       Path :: string(), SavePath :: string()}, List_torr :: [#torrent{}], 
	      List :: wxListCtrl:wxListCtrl()) ->
		     [#torrent{}].

addItem({Name, Status, Reference, Path, SavePath}, List_torr,List) ->
    ListItem = wxListItem:new(),

    case List_torr of
	[] ->
	    Index = 0;
	[#torrent{index = Old_index}|_T] ->
	    Index = Old_index + 1
    end,

    fix_list_item(Index, ListItem, Status, Name, List, 0),

    [#torrent{index = Index, listitem = ListItem, status = Status,
	     name = Name, reference = Reference, path = Path, 
	      savepath = SavePath, progress = 0}|List_torr].

%%--------------------------------------------------------------------
%% @doc
%% Manages buttons depending on status of the download.
%% @end
%%--------------------------------------------------------------------
-spec buttons_manage([wxButton:wxButton()], Status :: string()) ->
			    boolean().

buttons_manage([B102,B103,B104], Status) ->
    Status_atom = list_to_atom(Status),
    case Status_atom of
	started ->
	    wxButton:disable(B102),
	    wxButton:enable(B103),
	    wxButton:enable(B104);
	error ->
	    wxButton:enable(B102),
	    wxButton:disable(B103),
	    wxButton:enable(B104);
	stopped ->
	    wxButton:enable(B102),
	    wxButton:disable(B103),
	    wxButton:enable(B104)
    end.

%%--------------------------------------------------------------------
%% @doc
%% Changes name and status for ListItem, refreshes ListItem.
%% @end
%%--------------------------------------------------------------------
-spec fix_list_item(Index :: integer(), ListItem :: wxListItem:wxListItem(), Status :: string(), Name :: string(), List :: wxListCtrl:wxListCtrl(), Progress :: integer()) ->
			   ok.

fix_list_item(Index, ListItem, Status, Name, List, Progress) ->
    wxListItem:setId(ListItem, Index),
    wxListCtrl:insertItem(List, ListItem),
    wxListCtrl:setItem(List, Index, 0, Name, []),
    wxListCtrl:setItem(List, Index, 1, Status, []),
    wxListCtrl:setItem(List, Index, 2, integer_to_list(Progress), []),
    wxListCtrl:refreshItem(List, Index).
